package ran.judge.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ran.api.domain.dto.JudgeSubmitDTO;
import ran.api.domain.vo.UserExeResult;
import ran.api.domain.vo.UserQuestionResultVO;
import ran.constants.Constants;
import ran.constants.JudgeConstants;
import ran.enums.CodeRunStatus;
import ran.judge.domain.SandBoxExecuteResult;
import ran.judge.domain.UserSubmit;
import ran.judge.mapper.UserSubmitMapper;
import ran.judge.service.IJudgeService;
import ran.judge.service.ISandBoxService;

import java.util.ArrayList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ran
 * Date: 2025-11-22
 * Time: 17:37
 */
@Service
public class JudgeServiceImpl implements IJudgeService {

    @Autowired
    private ISandBoxService sandBoxService;
    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Override
    public UserQuestionResultVO doJudgeJavaCode(JudgeSubmitDTO judgeSubmitDTO) {
        // 先去沙盒中执行代码, 结果不为空, 并且是success: 2
        List<String> inputList = judgeSubmitDTO.getInputList();
        // 获取docker执行的结果
        SandBoxExecuteResult sandBoxExecuteResult = sandBoxService.exeJavaCode(judgeSubmitDTO.getUserId(),judgeSubmitDTO.getUserCode(),judgeSubmitDTO.getInputList());


        UserQuestionResultVO userQuestionResultVO = new UserQuestionResultVO();
        if (sandBoxExecuteResult != null && CodeRunStatus.SUCCEED.equals(sandBoxExecuteResult.getRunStatus())) {
            userQuestionResultVO = doJudge(judgeSubmitDTO, sandBoxExecuteResult, inputList, userQuestionResultVO);
        }else {
            // 发生了未知错误 或者 sandBoxExecuteResult 为null
            // 分数为0, pass为0, 错误信息打印上
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setPass(Constants.FALSE);
            if (sandBoxExecuteResult == null) {
                userQuestionResultVO.setExeMessage(CodeRunStatus.UNKNOWN_FAILED.getMsg());
            }else {
                userQuestionResultVO.setExeMessage(sandBoxExecuteResult.getExeMessage());
            }
            return userQuestionResultVO;
        }
        saveUserSubmit(judgeSubmitDTO, userQuestionResultVO);
        return userQuestionResultVO;
    }

    private void saveUserSubmit(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO) {
        // 存储到MySQL中
        UserSubmit userSubmit = new UserSubmit();
        BeanUtil.copyProperties(userQuestionResultVO,userSubmit);
        userSubmit.setUserId(judgeSubmitDTO.getUserId());
        userSubmit.setQuestionId(judgeSubmitDTO.getQuestionId());
        userSubmit.setExamId(judgeSubmitDTO.getExamId());
        userSubmit.setUserCode(judgeSubmitDTO.getUserCode());
        userSubmit.setProgramType(judgeSubmitDTO.getProgramType());
        userSubmit.setCreateBy(judgeSubmitDTO.getUserId());
        // 存储之前先删除最近存储的相同用户,竞赛,题目那一条数据
        userSubmitMapper.delete(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId,userSubmit.getUserId())
                .eq(UserSubmit::getQuestionId,userSubmit.getQuestionId())
                .isNull(judgeSubmitDTO.getExamId() == null,UserSubmit::getExamId)
                .eq(judgeSubmitDTO.getExamId() != null,UserSubmit::getExamId, judgeSubmitDTO.getExamId()));
        // 再添加进去, 保证是最新记录
        userSubmitMapper.insert(userSubmit);
    }

    private static UserQuestionResultVO doJudge(JudgeSubmitDTO judgeSubmitDTO,
                                                SandBoxExecuteResult sandBoxExecuteResult,
                                                List<String> inputList,
                                                UserQuestionResultVO userQuestionResultVO) {
        // 当前执行完成, 下面是判断逻辑
        // 1. 结果数量正确(进一步每个结果,比较空间,时间)
        List<String> exeOutputList = sandBoxExecuteResult.getOutputList();
        List<String> outputList = judgeSubmitDTO.getOutputList();
        List<UserExeResult> userExeResultList = new ArrayList<>();
        if (exeOutputList.size() == outputList.size()) {
            boolean pass = resultCompare(inputList, exeOutputList, outputList, userExeResultList);
            return assembleUserQuestionResultVO(judgeSubmitDTO, sandBoxExecuteResult, userQuestionResultVO, userExeResultList, pass);
        }
        userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
        userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
        userQuestionResultVO.setPass(Constants.FALSE);
        return userQuestionResultVO;
        // 2. 结果数量不正确
    }

    private static UserQuestionResultVO assembleUserQuestionResultVO(JudgeSubmitDTO judgeSubmitDTO, SandBoxExecuteResult sandBoxExecuteResult, UserQuestionResultVO userQuestionResultVO, List<UserExeResult> userExeResultList, boolean pass) {
        // 将执行集合放入List<UserExeResult> 设置到 UserQuestionResultVO 成员中, 不论下方是否成功
        userQuestionResultVO.setUserExeResultList(userExeResultList);

        if (!pass) {
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
            userQuestionResultVO.setPass(Constants.FALSE);
            return userQuestionResultVO;
        }
        // 2)空间是否合格
        if (sandBoxExecuteResult.getUseMemory() > judgeSubmitDTO.getSpaceLimit()) {
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_MEMORY.getMsg());
            userQuestionResultVO.setPass(Constants.FALSE);
            return userQuestionResultVO;
        }
        // 3)时间是否合格
        if (sandBoxExecuteResult.getUseTime() > judgeSubmitDTO.getTimeLimit()) {
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_TIME.getMsg());
            userQuestionResultVO.setPass(Constants.FALSE);
            return userQuestionResultVO;
        }
        // 都合格
        userQuestionResultVO.setPass(Constants.TRUE);
        int score = judgeSubmitDTO.getDifficulty() * JudgeConstants.DEFAULT_SCORE;
        userQuestionResultVO.setScore(score);
        return userQuestionResultVO;
    }

    private static boolean resultCompare(List<String> inputList, List<String> exeOutputList, List<String> outputList, List<UserExeResult> userExeResultList) {
        // 1)每个结果是否都正确
        boolean pass = true;
        for (int i = 0; i < exeOutputList.size(); i++) {
            // 将输入, 预计结果, 实际结果 放入到List<UserExeResult>中, 并添加到UserQuestionResultVO中
            UserExeResult userExeResult = new UserExeResult();
            userExeResult.setInput(inputList.get(i));
            userExeResult.setOutput(outputList.get(i));
            userExeResult.setExeOutput(exeOutputList.get(i));
            // 加入到集合元素中
            userExeResultList.add(userExeResult);
            if (!exeOutputList.get(i).equals(outputList.get(i))) {
                pass = false;
            }
        }
        return pass;
    }
}






















